package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.mapper.CartInfoMapper;
import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sun.javaws.exceptions.ExitException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Author: zm
 * @Date: 2021/8/20 22:53
 */
@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private CartInfoMapper cartInfoMapper;

    @Autowired
    private ProductFeignClient productFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;


    // 添加购物车
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addToCart(Long skuId, String userId, Integer skuNum) {

        //  有关于购物车缓存 redis  和  mysql 的操作问题！
        //  查询数据的时候，先看缓存，如果缓存没有，再看数据库并将数据load 到缓存中！
        //  购物车：再添加购物车时候，同时放入缓存一份！ insert into mysql and redis!
        String key = getCartKey(userId);
        if (!redisTemplate.hasKey(key)) {
            // 缓存中没有的 将数据加载到缓存中
            this.loadCartToCache(userId);
        }
        CartInfo existCartInfo = (CartInfo) redisTemplate.opsForHash().get(key, skuId.toString());

        // 原先直接从数据库中取  现在从缓存中取
//        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
//        wrapper.eq("sku_id", skuId);
//        wrapper.eq("user_id", userId);
//        CartInfo existCartInfo = cartInfoMapper.selectOne(wrapper);
        if (existCartInfo != null) {
            existCartInfo.setSkuNum(existCartInfo.getSkuNum() + skuNum);
            existCartInfo.setSkuPrice(productFeignClient.getSkuPrice(skuId));
            existCartInfo.setIsChecked(1);
            existCartInfo.setUpdateTime(new Timestamp(new Date().getTime()));
            cartInfoMapper.updateById(existCartInfo);

        } else {
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            CartInfo cartInfo = new CartInfo();
            cartInfo.setCreateTime(new Timestamp(new Date().getTime()));
            cartInfo.setUpdateTime(new Timestamp(new Date().getTime()));
            cartInfo.setSkuPrice(skuInfo.getPrice());
            cartInfo.setCartPrice(skuInfo.getPrice());
            cartInfo.setSkuNum(skuNum);
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuId(skuId);
            cartInfo.setUserId(userId);

            cartInfoMapper.insert(cartInfo);

            existCartInfo = cartInfo;
        }


        //  向缓存放入数据
        redisTemplate.opsForHash().put(key, skuId.toString(), existCartInfo);
        //  设置一个过期时间
        setCartKeyExpire(key);

    }

    // 查询购物车
    @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {
        List<CartInfo> cartInfoList = new ArrayList<>();

        if (StringUtils.isEmpty(userId)) {
            cartInfoList = this.getCartList(userTempId);
            return cartInfoList;
        }
        if (!StringUtils.isEmpty(userId)) {
            List<CartInfo> cartInfoTempList = this.getCartList(userTempId);
            if (!CollectionUtils.isEmpty(cartInfoTempList)) {

                cartInfoList = this.mergeToCartList(cartInfoTempList, userId);
                this.deleteCartList(userTempId);
            }

            if (CollectionUtils.isEmpty(cartInfoTempList)) {
                cartInfoList = this.getCartList(userId);
            }
        }
        return cartInfoList;
    }

    // 更新选中状态
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkCart(Long skuId, Integer isChecked, String userId) {
        CartInfo cartInfo = new CartInfo();
        cartInfo.setUpdateTime(new Timestamp(new Date().getTime()));
        cartInfo.setIsChecked(isChecked);
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        wrapper.eq("sku_id", skuId);
        cartInfoMapper.update(cartInfo, wrapper);

        String cartKey = this.getCartKey(userId);
        CartInfo cacheCartInfo = (CartInfo) redisTemplate.opsForHash().get(cartKey, skuId.toString());
        if (cacheCartInfo != null) {
            cacheCartInfo.setUpdateTime(new Timestamp(new Date().getTime()));
            cacheCartInfo.setIsChecked(isChecked);
            this.redisTemplate.opsForHash().put(cartKey, skuId.toString(), cacheCartInfo);
        }
        this.loadCartToCache(userId);
    }

    // 删除
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCart(String userId, Long skuId) {
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        wrapper.eq("sku_id", skuId);
        cartInfoMapper.delete(wrapper);

        String cartKey = this.getCartKey(userId);
//        redisTemplate.opsForHash().delete(cartKey,skuId);  // 删除缓存中数据
        Boolean flag = redisTemplate.boundHashOps(cartKey).hasKey(skuId.toString());
        if (flag) {
            redisTemplate.boundHashOps(cartKey).delete(skuId.toString());
        }
    }

    // 根据userid 获取 选中状态的商品
    @Override
    public List<CartInfo> getCartCheckedList(String userId) {
        String cartKey = this.getCartKey(userId);

//        List<CartInfo> cartInfoList = redisTemplate.boundHashOps(cartKey).values();
        List<CartInfo> cartInfoList = this.redisTemplate.opsForHash().values(cartKey);
        if (CollectionUtils.isEmpty(cartInfoList)) {
            return cartInfoList;
        }

        List<CartInfo> cartInfos = cartInfoList.stream().filter((cartInfo) -> {
            return cartInfo.getIsChecked() == 1;
        }).collect(Collectors.toList());
        return cartInfos;
    }

    // 合并购物车
    @Transactional(rollbackFor = Exception.class)
    public List<CartInfo> mergeToCartList(List<CartInfo> cartInfoTempList, String userId) {
        List<CartInfo> cartLoginList = this.getCartList(userId);
        Map<Long, CartInfo> cartLoginMap =
                cartLoginList.stream().collect(Collectors.toMap(CartInfo::getSkuId, cartInfo -> cartInfo));

        for (CartInfo cartInfo : cartInfoTempList) {
            Long skuId = cartInfo.getSkuId();
            if (cartLoginMap.containsKey(skuId)) {
                CartInfo cartInfoLogin = cartLoginMap.get(skuId);
                cartInfoLogin.setSkuNum(cartInfo.getSkuNum() + cartInfoLogin.getSkuNum());
                cartInfoLogin.setUpdateTime(new Timestamp(new Date().getTime()));

                if (cartInfo.getIsChecked() == 1) {
                    cartInfoLogin.setIsChecked(1);
                }
                cartInfoMapper.updateById(cartInfoLogin);
            } else {
                cartInfo.setUserId(userId);
                cartInfo.setUpdateTime(new Timestamp(new Date().getTime()));
                cartInfo.setCreateTime(new Timestamp(new Date().getTime()));
                cartInfoMapper.insert(cartInfo);
            }
        }

        List<CartInfo> cartInfoList = this.loadCartToCache(userId);
        return cartInfoList;

    }

    // 删除未登录购物车数据
    @Transactional(rollbackFor = Exception.class)
    public void deleteCartList(String userTempId) {
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userTempId);
        cartInfoMapper.delete(wrapper);

        String cartKey = this.getCartKey(userTempId);
        Boolean flag = redisTemplate.hasKey(cartKey);
        if (flag) {
            redisTemplate.delete(cartKey);
        }
    }

    // 根据 userid 获取购物车中数据
    private List<CartInfo> getCartList(String userId) {
        List<CartInfo> cartInfoList = new ArrayList<>();
        if (StringUtils.isEmpty(userId)) {
            return cartInfoList;
        }
        String cartKey = this.getCartKey(userId);
        cartInfoList = redisTemplate.opsForHash().values(cartKey);
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            cartInfoList.sort((o1, o2) -> {
                return DateUtil.truncatedCompareTo(o2.getUpdateTime(), o1.getUpdateTime(), Calendar.SECOND);
            });
        } else {
            cartInfoList = this.loadCartToCache(userId);
        }
        return cartInfoList;
    }

    // 通过userId 查询购物车并放入缓存！
    @Override
    public List<CartInfo> loadCartToCache(String userId) {
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        wrapper.orderByDesc("update_time");
        List<CartInfo> cartInfoList = cartInfoMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(cartInfoList)) {
            return cartInfoList;
        }

        Map<String, CartInfo> map = new HashMap<>();
        for (CartInfo cartInfo : cartInfoList) {
            cartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
            map.put(cartInfo.getSkuId().toString(), cartInfo);
        }

        String cartKey = this.getCartKey(userId);
        redisTemplate.opsForHash().putAll(cartKey, map);
        // 設置过期时间
        this.setCartKeyExpire(cartKey);

        return cartInfoList;
    }

    //  获取购物车的key！
    private String getCartKey(String userId) {
        //  缓存的类型选中谁? hash  hset key field value   hget key field;
        //  key = user:userId:cart  field = skuId  value = cartInfo;
        return RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
    }

    //  设置过期时间
    private void setCartKeyExpire(String key) {
        //  设置一个过期时间
        redisTemplate.expire(key, RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
    }
}
